﻿Feature: Plugins
	As a developer, I want to be able to define extension points
	for my application, find and load plugins that are based on my
	extension points, and interact with the plugins before dropping them,
	thus enhancing my application while keeping it secure.

# F1. an extension point can be any public interface.
# F2. the consuming app asks for extensions by interface type.
# F3. the plugin loader discovers assemblies at a (configurable) location.
# F4. each discovered assembly is scanned for a plugin entry point.
## F4a. a plugin entry point answers the question: "does your assembly contain one of these?"
## F4b. a plugin entry point can then be used to create a plugin automator
# F5. plugin automators are used to communicate securely with plugins
## F5a. they are marshal-by-ref
## F5b. they expose simple, serializable methods
### F5b1. "set this property"
### F5b2. "get this property"
### F5b3. "call this method"
### F5b4. complex types must be serializable or marshal-by-ref
# F6. consuming applications can define automator proxies
## F6a. a well-formed proxy will implement the extension interface
## F6b. a proxy already "knows what to say" to an automator
## F6c. the consuming application remains as strongly-typed as possible
# F7. all plugins are loaded into auxiliary AppDomains
## F7a. hence all the remoting restrictions
## F7b. plugins that violate any rules (undefined) can be dropped
## F7c. plugins that are not being used can be dropped
# F8. all plugin assemblies must pass security policy
## F8a. assembly must be in designated location.
## F8b. assembly must expose a correct plugin hash.
### F8b1. hash is exposed through assembly decoration
### F8b2. hash corresponds with computed hash provided by System.Security.Policy.Hash
### F8b3. new assembly attribute: PluginAttribute -- ex. [assembly: Plugin(typeof({extension point interface}))]
## F8c. assembly must expose a correct plugin contract
### F8c1. equivalent to typeof({extension point interface}).AssemblyQualifiedName
## F8d. all criteria will be evaluated prior to loading
### F8d1. new type: PluginAssembly
### F8d2. new marshal-by-ref object: PluginScanner
### F8d3. PluginAssembly accepts FileInfo as constructor argument: var plugin = new PluginAssembly(pluginFile);
### F8d4. new serializable POCO: PluginScanResults
### F8d5. PluginScanner takes FileInfo, returns list of PluginScanResults
### F8d6. PluginAssembly uses PluginScanner remotely, parses PluginScanResults
### F8d7. usage: plugin.Implements<TPlugin>() or plugin.Implements(Type pluginContract)
# F9. PluginAssembly is then used to load desired plugin implementations
## F9a. via plugin.Load<TPlugin>() or plugin.Load(Type pluginContract)
### F9a1. 
## F9b. returns PluginAutomator
## F9c. automator.Plugins returns read-only collection of WrappedPlugin objects
### F9c1. WrappedPlugin: { Name (string), Namespace (string), Contract (string) }
## F9d. automator.GetValue(string name) returns IDictionary<WrappedPlugin, object>
### F9d1. automator.PreValueRead returns IObservable<PluginValueReadRequest>
#### F9d1a. PluginValueReadRequest: { Name (string) }
### F9d2. automator.PostValueRead returns IObservable<PluginValueReadResponse>
#### F9d2a. PluginValueReadResponse: { Name (string), Result (object) }
## F9e. automator.SetValue(string name, object value) sets on each wrapped plugin
### F9e1. automator.PreValueWrite returns IObservable<PluginValueWriteRequest>
#### F9e1a. PluginValueWriteRequest: { Name (string), Value (object) }
### F9e2. automator.PostValueWrite returns IObservable<PluginValueWriteResponse>
#### F9e2a. PluginValueWriteResponse: { Name (string), Value (object) }
## F9f. automator.Invoke(string name, object[] values) invokes on each wrapped plugin
### F9f1. automator.PreMethodCall returns IObservable<PluginMethodCallRequest>
#### F9f1a. PluginMethodCallRequest: { Name (string), Values (List<object>) }